/*
 * Copyright (c) 2012 Universidad Antonio de Nebrija.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License v2.0
 * which accompanies this distribution, and is available at
 * http://www.apache.org/licenses/LICENSE-2.0.html
 * 
 * Contributors:
 *    Universidad Antonio de Nebrija - initial API, implementation and documentation
 */
package com.nebrija.riif.model.saver.bufferedwriter;

import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import com.nebrija.riif.model.AssertValidation;
import com.nebrija.riif.model.FailMode;
import com.nebrija.riif.model.Parameter;
import com.nebrija.riif.model.RIIFProperties;
import com.nebrija.riif.model.saver.AssertValidationSaver;
import com.nebrija.riif.model.saver.RIIFPropertiesSaver;
import com.nebrija.riif.model.saver.RIIFSaverFactory;

/**
 * Implementation of an RIIFPropertiesWriterFormatSaver that writes the object to a BufferedWriter
 * @author asanchep
 *
 */
public class RIIFPropertiesWriterFormatSaver implements RIIFPropertiesSaver {

	public static final String CONSTANT_TOKEN = "constant";
	public static final String PARAMETER_TOKEN = "parameter";
	public static final String FAIL_MODE_TOKEN = "fail_mode";
	public static final String ASSIGN_TOKEN = "assign";
	public static final String NULL_FAIL_MODE = "null";
	
	/** Writer where the information about the object is sent */
	private BufferedWriter out;
	/** Factory used to create other elements of the saver family */
	private RIIFSaverFactory factory;
	
	/**
	 * Creates an RIIFPropertiesWriterFormatSaver
	 * @param bw Writer where the information about the object is sent
	 * @param factory Factory used to create other elements of the saver family
	 */
	public RIIFPropertiesWriterFormatSaver (BufferedWriter bw, RIIFSaverFactory factory){
		out=bw;
		this.factory=factory;
	}
	
	@Override
	public void save(RIIFProperties element) {
		if(out==null){
			return;
		}
		
		// Detect which kind of element we are processing
		String rtype=CONSTANT_TOKEN;
		if(element instanceof Parameter){
			rtype=PARAMETER_TOKEN;
		}else if (element instanceof FailMode){
			rtype=FAIL_MODE_TOKEN;
		}
		
		try{
			// Do not consider null element
			if(!NULL_FAIL_MODE.equals(element.getName())){
				// print information
				out.append(rtype).append(" ").append(element.getName());
				Object type= element.getProperty(RIIFProperties.TYPE_KEY);
				Object value = element.getValue();
				// If there is a type, print it
				if(type!=null){
					out.append(" : ").append(type.toString());
				}
				// If there is a value, print it
				if (value!=null){
					out.append(" := ").append(value.toString());
				}
				out.append(";\n");
			}

			// For every property, print the assign sentence
			HashMap<String,Object> properties = element.getProps();
			for(String key:properties.keySet()){
				// exclude type and value, which were already printed in the definition
				if(RIIFProperties.TYPE_KEY.equals(key) || RIIFProperties.VALUE_KEY.equals(key)){
					continue;
				}
				Object val = properties.get(key);
				if(val==null){
					continue;
				}
				// Print the assignment
				out.append(ASSIGN_TOKEN).append(" ")
							.append(element.getName()).append("'").append(key).append(" = ")
							.append(val.toString()).append(";\n");
				
				// Retrieve the assertions for this property
				ArrayList<AssertValidation> assertions = element.getAssertions(key);
				if (assertions==null || assertions.size()==0){
					continue;
				}
				//Delegate the assertion saving to the appropriate class
				AssertValidationSaver saver = factory.getAssertValidationSaver();
				for (AssertValidation assertVal: assertions){
					saver.save(assertVal);
				}
			}
			out.append("\n");
			
			out.flush();
		}catch(IOException ioe){
			ioe.printStackTrace();
		}
	}

}
